"""总览页面视图函数业务逻辑模块"""
import traceback
from datetime import datetime, timedelta

import numpy as np
import pandas as pd

from air_web.config.config import config
from air_web.web_flask.bll.base_bll import BaseBll
from air_web.web_flask.bll.model_map import ModelMap
from air_web.web_flask.common.constants import (  # , C_CONS, POWERLOAD_AREA,
    ORG_MAP,
    ReturnType,
)


class ReportBll(BaseBll):
    """总览页面视图函数业务逻辑类"""

    C_CONS = config.get("C_CONS", "c_cons")
    CITY_TOTAL_CRITICAL = config.get(
        "CITY_TOTAL_CRITICAL", "city_total_critical"
    )
    ORGNO_TYPEID_15MIN = config.get("ORGNO_TYPEID_15MIN", "orgno_typeid_15min")

    def __init__(
        self,
    ):
        """
        如果当前页面用到mysql则init_mysql_dal=True，self.sql_dal就会提供mysql实例，不用到则传False
        如果当前页面用到es则init_es_dal=True，self.es_dal就会提供es实例，不用到则传False
        """
        super().__init__(init_mysql_dal=True, init_es_dal=True)

    def proc_city_day(self, rules, data_date, time_list):
        # 获取数据,只要8：00到23：00的
        start_time = data_date + " 08:00:00"
        end_time = data_date + " 23:00:00"
        rules_new = rules + [
            ("data_time", "query", ">=", start_time),
            ("data_time", "query", "<=", end_time),
        ]
        columns = ["org_no", "org_name", "p_kt_sum", "data_time"]
        res_df = self.sql_dal.sql_pandas.query_by_rules(
            self.ORGNO_TYPEID_15MIN, rules_new, columns=columns
        )
        if res_df.empty:
            self.logger.warning(
                f"查询数据为空,table:{self.ORGNO_TYPEID_15MIN},rules:{rules_new}"
            )
            return res_df, []
        self.logger.info(
            f"查询数据条数:{len(res_df)},table:{self.ORGNO_TYPEID_15MIN},rules:{rules_new}"
        )
        res_df["p_kt_sum"] = res_df["p_kt_sum"] / 10000  # 转换单位：万Kw

        # 排序
        res_df = res_df.sort_values(["org_no", "data_time"])

        # 筛选多余的点,只要8：00到23：00的每半小时的点
        counts = res_df.groupby(["org_no", "org_name"])[
            "data_time"
        ].count()  # 统计每个地市的点数
        min_count = counts.min()  # 获取点数最小值

        default_time_list = (
            pd.date_range(
                start=start_time, periods=(min_count + 1) / 2, freq="30min"
            )
            .strftime("%H:%M")
            .tolist()
        )
        time_list = (
            list(set(default_time_list) & set(time_list))
            if time_list
            else default_time_list
        )
        time_list.sort()
        res_df["data_time"] = res_df["data_time"].dt.strftime("%H:%M")
        res_df = res_df.loc[res_df["data_time"].isin(time_list)]

        # 转换结构
        res_df = (
            res_df.groupby(["org_no", "org_name"])["p_kt_sum"]
            .apply(list)
            .reset_index()
        )
        res_df[time_list] = pd.DataFrame(res_df["p_kt_sum"].values.tolist())
        res_df = res_df.drop("p_kt_sum", axis=1)
        res_df = res_df.set_index(["org_no", "org_name"])

        return res_df, time_list

    def get_on5_list(self):
        sql = "select org_no from real_org_no where org_level = 1"
        df = self.sql_dal.sql_pandas.query(sql)
        on5_list = df["org_no"].tolist()
        return on5_list

    def get_on5_sort_df(self):
        # 地市显示顺序
        sql = "select distinct sort_no, on5 as org_no from {}".format(
            self.CITY_TOTAL_CRITICAL
        )
        on5_sort_df = self.sql_dal.sql_pandas.query(sql)
        return on5_sort_df

    def proc_city_chain(self, pre_date, fol_date, on5_list, time_list):
        if not on5_list:
            on5_list = self.get_on5_list()
     #   pre_date = self.get_baseline_date(fol_date)
        if pre_date is None:
            return pd.DataFrame(), pd.DataFrame(), []

        rules = [
            ("org_no", "query", "in", on5_list),
            ("type_id", "query", "=", 0),
        ]
        pre_df, _ = self.proc_city_day(rules, pre_date, time_list)
        fol_df, time_list = self.proc_city_day(rules, fol_date, time_list)
        if pre_df.empty or fol_df.empty:
            return pd.DataFrame(), pd.DataFrame(), []

        # 压降值=昨天时间点最大负荷 - 今天时间点最大负荷
        diff_df = pre_df - fol_df
        # 压降率= 压降值 / 昨天时间点最大负荷
        rate_df = (diff_df / pre_df).round(4)

        # 删除一列或者一行中所有值为NaN的列
        diff_df = diff_df.dropna(axis=1, how="all")
        diff_df = diff_df.dropna(axis=0, how="all")

        # 让rate_df的列和diff_df的列相同
        rate_df = rate_df[diff_df.columns]

        # 添加全省行
        column_sums = diff_df[diff_df[time_list] > 0].sum()
        province_row = pd.Series(column_sums, name=(99, "全省压降"))
        diff_df = diff_df.append(province_row)
        # 所有时间的diff合并为一个字段
        diff_df["diff"] = diff_df.apply(
            lambda row: row.values.tolist(), axis=1
        )
        diff_df["p_avg"] = diff_df[diff_df[time_list] > 0].mean(
            axis=1
        )  # 压降平均值
        diff_df["p_max"] = diff_df[diff_df[time_list] > 0].max(axis=1)  # 压降最大值

        # 删除一列或者一行中所有值为NaN的列
        # rate_df = rate_df.dropna(axis=1, how="all")
        # rate_df = rate_df.dropna(axis=0, how="all")
        # 实测和基线都为0的(0/0=nan)
        rate_df = rate_df.fillna(0.0)
        # -inf 改为None
        rate_df.replace({-np.inf: None}, inplace=True)
        rate_df["rate"] = rate_df.apply(
            lambda row: row.values.tolist(), axis=1
        )  # 所有时间的rate合并为一个字段

        return diff_df, rate_df, time_list

    def get_city_chain(self, pre_date, fol_date, on5_list, time_list):
        """获取各地市环比报表"""
        try:
            # 合并
            diff_df, rate_df, time_list = self.proc_city_chain(
                pre_date, fol_date, on5_list, time_list
            )
            if diff_df.empty:
                return ReturnType.EMPTY
            chain_res_df = pd.merge(
                diff_df[["diff", "p_avg", "p_max"]],
                rate_df[["rate"]],
                left_index=True,
                right_index=True,
                how="left",
            )
            chain_res_df.replace([np.inf, -np.inf, np.nan], None, inplace=True)
            chain_res_df = chain_res_df.mask(chain_res_df.isnull(), None)
            chain_res_df = chain_res_df.reset_index()

            # 地市显示顺序
            on5_sort_df = self.get_on5_sort_df()
            chain_res_df = chain_res_df.merge(
                on5_sort_df, on="org_no", how="left"
            )
            chain_res_df = chain_res_df.sort_values("sort_no")
            chain_res_df = chain_res_df.drop(["org_no", "sort_no"], axis=1)

            # 转换格式
            p_list = chain_res_df.to_dict("record")
            p_list[-1]["rate"] = []  # 全省
            res_dict = {"p_value": p_list, "time_list": time_list}
            return res_dict
        except:
            self.logger.error(traceback.format_exc())
            return ReturnType.ERROR

    def export_chain_excel(self, pre_date, fol_date, on5_list, time_list):
        try:
            diff_df, rate_df, time_list = self.proc_city_chain(
                pre_date, fol_date, on5_list, time_list
            )
            if diff_df.empty:
                return pd.DataFrame()
            chain_res_df = pd.merge(
                diff_df,
                rate_df,
                on=["org_no", "org_name"],
                how="left",
                suffixes=("_压降值", "_压降率"),
            )
            chain_res_df = chain_res_df.drop(["diff", "rate"], axis=1)
            # chain_res_df = chain_res_df.dropna(
            #     axis=1, how="all"
            # )  # 删除一列中所有值为NaN的列
            chain_res_df.replace([np.inf, -np.inf], None, inplace=True)
            chain_res_df = chain_res_df.sort_index(axis=1)
            chain_res_df = chain_res_df.reset_index()

            # 地市显示顺序
            on5_sort_df = self.get_on5_sort_df()
            chain_res_df = chain_res_df.merge(
                on5_sort_df, on="org_no", how="left"
            )
            chain_res_df = chain_res_df.sort_values("sort_no")
            chain_res_df = chain_res_df.drop(["org_no", "sort_no"], axis=1)
            return chain_res_df
        except:
            self.logger.error(traceback.format_exc())
            return ReturnType.ERROR
